# Sass 中的数据类型(值类型)

  • Number, 可以是有单位或没有单位的值, 比如 12100px

  • String, 可以是有引号或没有引号的值, 比如 "Helvetica Neue"bold

  • Color, 可以通过十六进制表示或名称引用,如 #c6538cblue ,或从函数返回,如 rgb(107, 113, 127)hsl(210, 100%, 20%)

  • List, 必须用空格或逗号隔开,可以用方括号 [] 括起, 也可以不用, 比如 1.5em 1em 0 2emHelvetica, Arial, sans-serif, 或是 [col1-start].

Sass 特有的值类型:

  • Boolean , truefalse

  • null

  • Map 键值对映射,圆括号包裹, 比如 ("background": red, "foreground": pink)

  • Function , 由 get-function() 返回并由 call() 调用的函数引用。

# Number

Sass 中的数字有两个组成部分:数字本身和它的单位。例如,在 16px 中,数字是 16,单位是 px 。数字可以没有单位,也可以有复杂的单位。

$num1: 100; // 100
$num2: 0.8; // 0.8
$num3: 16px; // 16px
$num4: 5px * 2px; // 10px*px (read "square pixels")
1
2
3
4

Sass 中的数字支持与 CSS 数字相同的格式,包括科学记数法,它在数字和它的 10 的幂之间用 e 书写。由于浏览器中对科学符号的支持一直不稳定,所以 Sass 总是将其编译为完全扩展的数字。

$num1: 5.2e3; // 5200
$num2: 6e-2; // 0.06
1
2

注意:Sass 不区分整数和小数,所以例如 5 / 2 返回 2.5 而不是 2 。这与JavaScript的行为相同,但与许多其他编程语言不同。

# 单位

Sass 对单位的操作是基于现实世界的单位计算的。当两个数相乘时,它们的单位也相乘。当一个数除以另一个数时,结果取第一个数的分子单位和第二个数的分母单位。一个数的分子和/或分母可以有任意数量的单位。

$num1: 4px * 6px; // 24px*px (read "square pixels")
$num2: 5px / 2s; // 2.5px/s (read "pixels per second")
$num3: 5px * 30deg / 2s / 24em; // 3.125px*deg/s*em (read "pixel-degrees per second-em")
$num4: 20deg / 1s; // 20deg/s
$num5: 1 / $num4; // 0.05s/deg
1
2
3
4
5

但是,CSS 是不支持像 square pixels 这样的复杂单位,使用带有复杂单位的数字作为属性值将会产生错误。如果没有得到正确的单位,这通常意味着你的计算出了问题。

可以使用 @debug 规则来检查任何变量或表达式的单位。

Sass 将在兼容的单元之间自动转换,尽管它将为结果选择哪个单元取决于您使用的 Sass 的哪个实现版本。如果你试图组合不兼容的单位,比如 1in + 1em , Sass将抛出一个错误。

// CSS defines one inch as 96 pixels.
@debug 1in + 6px; // 102px or 1.0625in
@debug 1in + 1s;
//     ^^^^^^^^
// Error: Incompatible units s and in.
1
2
3
4
5

在现实世界的单位计算中,如果分子包含与分母单位兼容的单位(如 96px / 1in ),它们就会抵消。

$num1: (96px / 1in); // 1
1

注意,要避免使用像 #{$number}px 这样的插值。这实际上并没有创建一个数字,它创建了一个看起来像数字的无引号字符串,但不能用于任何数字操作或函数。定义 $number 变量时可以带上单位 px ,或者写为 $number * 1px

Sass 的百分比和其他单位一样。它们不能与小数互换,因为在 CSS 中小数和百分比表示不同的东西。例如,50% 是一个以 % 为单位的数字,Sass 认为它与 0.5 不同。

可以使用单位算术在小数和百分比之间进行转换。$percentage / 100% 将返回相应的小数,而$decimal * 100% 将返回相应的百分比。还可以使用 math.percentage() 函数作为 $decimal * 100% 的更显式的写法。

# 精度(Precision)

Sass 数字支持小数点后最多 10 位的精度。这意味着:

  • 生成的 CSS 只包含小数点后的数字的前 10 位。
  • ==>= 这样的运算,如果两个数字在小数点之后的前 10 位都是相同的,则认为它们是相等的,小数点之后 10 位以上数字直接被忽略。
  • 如果一个数字与一个整数的距离小于0.0000000001,对于像 list.nth() 这样需要整数参数的函数来说,它被认为是一个整数。
$num1: 0.012345678912345; // 0.0123456789
$num2: 0.01234567891 == 0.01234567899; // true
$num3: 1.00000000009; // 1
$num4: 0.99999999991; // 1
1
2
3
4

# String

字符串是字符序列(Unicode 码位)。Sass 支持两种内部结构相同但呈现方式不同的字符串:带引号的字符串,如 "Helvetica Neue",以及不带引号的字符串(也称为标识符),如 bold

可以使用 string.unquote() 函数将带引号的字符串转换为不带引号的字符串,也可以使用 string.quote() 函数将不带引号的字符串转换为带引号的字符串。

@use "sass:string";

@debug string.unquote(".widget:hover"); // .widget:hover
@debug string.quote(bold); // "bold"
1
2
3
4

# 转义(Escapes)

所有 Sass 字符串都支持标准的 CSS 转义码:

  • 除了所有字母和数字以外之外的任何字符都可以通过在前面写 \ 来作为字符串的一部分
  • 任何字符都可以作为字符串的一部分,方法是在 \ 后面加上十六进制 Unicode 码,不同字符的 Unicode 码用空格分隔。
@debug "\""; // '"'
@debug \.widget; // \.widget
@debug "\a"; // 一个不可见的换行符
@debug "line1\a line2"; // "line1换行line2"
@debug "Nat + Liz \1F46D"; // "Nat + Liz 👭"
1
2
3
4
5

# 带引号的 string

带引号的字符串写在单引号或双引号之间,如 "Helvetica Neue"。可以包含插值,以及任何未转义的字符,除了:

  • \ , 需要使用 \\ 来转义; '", 需要使用 \'\" 来转义
  • 换行, 需要写为 \a 并加一个空格与后面的内容隔开

带引号的字符串保证被编译成与原始 Sass 字符串内容相同的 CSS 字符串。

@debug "Helvetica Neue"; // "Helvetica Neue"
@debug "C:\\Program Files"; // "C:\\Program Files"
@debug "\"Don't Fear the Reaper\""; // "\"Don't Fear the Reaper\""
@debug "line1\a line2"; // "line1\a line2"

$roboto-variant: "Mono";

@debug "Roboto #{$roboto-variant}"; // "Roboto Mono"
1
2
3
4
5
6
7
8

带引号的字符串放入插值中时,它的引号将被删除。这使得编写包含选择器的字符串变得很容易,例如,选择器可以被注入到样式规则中,而不需要添加引号。

# 不带引号的字符串

不带引号的字符串就是写 CSS 标识符。它们可能包括任何地方的插值。

@debug bold; // bold
@debug -webkit-flex; // -webkit-flex
@debug --123; // --123

$prefix: ms;

@debug -#{$prefix}-flex; // -ms-flex
1
2
3
4
5
6
7

当然,并不是所有的标识符都被解析为不带引号的字符串:

  • CSS 颜色名称被解析为 color 类型。
  • null 被解析为 Sass 的 null 值。
  • truefalse 被解析为 boolean 类型。
  • not, and, or 被解析为 boolean 操作符

正因为如此,除非您专门编写使用不带引号的字符串的 CSS 属性值,否则编写带引号的字符串通常是一个好主意。

当解析未加引号的字符串时,转义的文字文本将作为字符串的一部分进行解析。例如,\a 被解析为字符\a空格。为了确保在CSS中具有相同含义的未加引号的字符串以相同的方式解析,这些转义都是规范化的。对于每个代码点,不管是转义的还是未转义的:

  • 如果它是一个有效的标识符字符,它将不转义地包含在未加引号的字符串中。例如,\1F46D 返回未加引号的字符串 👭
  • 如果它是除换行符或制表符之外的可打印字符,则它包含在 \ 之后。例如,\21 返回未加引号的字符串 \!
  • 否则,小写 Unicode 转义将包含在末尾的空格中。例如,\7Fx返回未加引号的字符串\7f x
@use "sass:string";

@debug \1F46D; // 👭
@debug \21; // \!
@debug \7Fx; // \7f x
@debug string.length(\7Fx); // 5
1
2
3
4
5
6

# 字符串的索引

Sass有许多字符串函数,它们接受或返回数字作为索引,这些数字指的是字符串中的字符。

Sass 的字符串中第一个字符的索引为 1,不同于大多数语言索引从 0 开始。

-1 表示字符串中的最后一个字符,-2 表示倒数第二个字符,以此类推。

@use "sass:string";

@debug string.index("Helvetica Neue", "Helvetica"); // 1
@debug string.index("Helvetica Neue", "Neue"); // 11
@debug string.slice("Roboto Mono", -4); // "Mono"
1
2
3
4
5

# Color

Sass 颜色可以写成:

  • 十六进制代码, 比如 #f2ece4,或者包含透明值的 #b37399aa
  • CSS 颜色名称, 比如 midnightblue , transparent
  • 函数, 比如 rgb()rgba()hsl()hsla()
@debug #f2ece4; // #f2ece4
@debug #b37399aa; // rgba(179, 115, 153, 67%)
@debug midnightblue; // #191970
@debug rgb(204, 102, 153); // #c69
@debug rgba(107, 113, 127, 0.8); // rgba(107, 113, 127, 0.8)
@debug hsl(228, 7%, 86%); // #dadbdf
@debug hsla(20, 20%, 85%, 0.7); // rgb(225, 215, 210, 0.7)
1
2
3
4
5
6
7

Sass 支持许多有用的 color 函数来在现有颜色的基础上创建新的颜色。可以通过混合颜色或缩放颜色的色相、饱和度或明度。详情参考内置模块章节。

$venus: #998099;

@debug scale-color($venus, $lightness: +15%); // #a893a8
@debug mix($venus, midnightblue); // #594d85
1
2
3
4

# List

列表包含其他值的序列。在 Sass 中,列表中的元素可以用逗号分隔,如 Helvetica, Arial, sans-serif ,或空格分隔,如 10px 15px 0 0 ,但不能混合使用空格和逗号。

与大多数其他语言不同,Sass 中的列表不需要特殊的方括号,任何用空格或逗号分隔的表达式都可以算作一个列表。当然,也允许使用方括号来编写列表,如 [a b][a, b] 。这对使用 grid-template-columns 来说是非常有用的。

Sass 列表可以包含任意个元素,甚至是包括 0 个。单元素列表可以写成 (a,)[a] ,零元素列表可以写成 ()[] 。此外,对待一个单独存在的不在列表中的值,所有内置的列表函数都将他们视为列表,比如 a 对列表函数来说就像是 (a)[a] 似的,这意味着不需要显式地创建像 (a)[a] 这样的单个元素的列表。

$border1: (1px solid #f00);
$border2: (1px, solid, #f00);
$border3: [1px solid #f00];
$border4: [1px, solid, #f00];

.div1 {
  border: $border1;
}

.div2 {
  border: $border2;
}

.div3 {
  border: $border3;
}

.div4 {
  border: $border4;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

编译后的 css :

.div1 {
  border: 1px solid #f00;
}

.div2 {
  border: 1px, solid, #f00;
}

.div3 {
  border: [1px solid #f00];
}

.div4 {
  border: [1px, solid, #f00];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 索引

Sass 的列表中第一个元素的索引为 1,不同于大多数语言索引从 0 开始。

-1 表示列表中的最后一个元素,-2 表示倒数第二个元素,以此类推。

# 访问某个元素

使用 list.nth($list, $index) 函数获取一个列表中的值,第一个参数表示列表,第二个参数表示要获取元素的索引。

@use 'sass:list';

@debug list.nth(10px 12px 16px, 2); // 12px
@debug list.nth([line1, line2, line3], -1); // line3
1
2
3
4

# 遍历列表

使用 @each $ele in $list 语句来遍历一个列表, $ele 表示当前循环的列表元素, $list 表示要遍历的列表。

$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}
1
2
3
4
5
6
7
8
9

编译后的 css :

.icon-40px {
  font-size: 40px;
  height: 40px;
  width: 40px;
}

.icon-50px {
  font-size: 50px;
  height: 50px;
  width: 50px;
}

.icon-80px {
  font-size: 80px;
  height: 80px;
  width: 80px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 追加元素

使用 list.append($list, $val) 函数,第一个参数为目标列表,第二个参数为要追加的元素,并返回一个在末尾追加了新元素的的新的列表。注意,因为 Sass 列表是不可变的,所以它不会修改原始列表。

@use 'sass:list';

@debug list.append(10px 12px 16px, 25px); // 10px 12px 16px 25px
@debug list.append([col1-line1], col1-line2); // [col1-line1, col1-line2]
1
2
3
4

# 查找元素的索引

使用 list.index($list, $value) 函数,第一个参数为目标列表,第二个参数为目标元素,找到元素返回索引值,找不到返回 null

@use 'sass:list';

@debug list.index(1px solid red, 1px);  // 1
@debug list.index(1px solid red, solid);  // 2
@debug list.index(1px solid red, dashed);  // null
1
2
3
4
5

# 列表的不可变性(Immutability)

Sass 中的列表是不可变的,这意味着列表值的内容永远不会改变。Sass 的列表函数只能返回一个新的列表,而不是修改原始列表。

不可变性有助于在各个地方共用一个列表时,避免因为列表被更改而出现一些 Bug。

所以,如果一个变量表示的列表需要修改,应该将新的列表赋值给这个变量。

@use 'sass:list';

$list: (10px 12px 16px);

$list: list.append($list, 25px);

@debug $list; // 10px 12px 16px 25px
1
2
3
4
5
6
7

# 参数列表

当你声明一个接收任意参数的 mixin 或 function 时,任意参数这个变量将会是一个特殊的列表,称为 参数列表 。这个变量就像是一个列表,包含传递给 mixin 或 function 的所有参数,

如果用户传递的关键字参数,可以将参数列表传递给 meta.keywords() 函数,将返回一个 map 类型的值。

@use "sass:meta";

@mixin syntax-colors($args...) {
  // map 类型的值 (string: #080, comment: #800, variable: #60b)
  @debug meta.keywords($args);

  @each $name, $color in meta.keywords($args) {
    pre span.stx-#{$name} {
      color: $color;
    }
  }
}

@include syntax-colors(
  $string: #080,
  $comment: #800,
  $variable: #60b,
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

编译后的 css :

pre span.stx-string {
  color: #080;
}

pre span.stx-comment {
  color: #800;
}

pre span.stx-variable {
  color: #60b;
}
1
2
3
4
5
6
7
8
9
10
11

# Map

map 用来表示键值对的映射,格式为 (key1: value, key2: value) ,其中 key 必须唯一。

$tag: (
  "primaryColor": #f00,
  "size": 16px
);

$empty: ();
1
2
3
4
5
6

与列表不同, map 必须用圆括号 () 括起来。空的 map 写为 ()

但是,空列表也是写为 (),怎么空的 map 和空列表一样呢?

因为,() 它既是映射又是列表。事实上,所有的 map 都可以算作列表,每个 map 都算是一个包含键值对的列表,每个列表元素就是一组键值对。例如 (a: b, c: d) 表示为 (a b, c d)

map 允许使用任何 Sass 值作为它的 key 。 Sass 将会用 == 操作符来判断两个 key 是否重复。

大多数情况下,强烈推荐使用带引号的字符串作为 map 的 key 。因为有些值,比如颜色名,看起来像未加引号的字符串,但实际上不是字符串而是其他类型。为了避免混乱的问题,字符串作为 key 时都应该加上引号。

由于 map 不是合法的 CSS 值,它们自己不会做很多事情。这就是为什么 Sass 提供了一堆函数来创建 map 并访问它们包含的值。

# 访问 map 的值

通过 map.get($map, $key) 函数来访问值,第一个参数表示 map ,第二个参数表示对应的 key ,指定的 key 不存在时返回 null

@use "sass:map";

$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.get($font-weights, "medium"); // 500
@debug map.get($font-weights, "extra-bold"); // null
1
2
3
4
5
6

# 遍历 map

通过 @each 语句对一个 map 进行遍历。

$colors: (
  "red": #f00,
  "green": #0f0,
  "blue": #00f,
);

@each $key, $value in $colors {
  .icon-#{$key} {
    color: $value;
  }
}
1
2
3
4
5
6
7
8
9
10
11

编译后的 css :

.icon-red {
  color: #f00;
}

.icon-green {
  color: #0f0;
}

.icon-blue {
  color: #00f;
}

1
2
3
4
5
6
7
8
9
10
11
12

# 修改 map

向 map 添加新的键值对或修改已存在的键值对。使用 map.set($map, $key, $value) 函数, 它返回设置完成后的新的 map ,不会修改原 map 。

@use "sass:map";

$colors: (
  "red": #f00,
  "green": #0f0,
  "blue": #00f,
);

@debug map.set($colors, "red", #a11);
// ("red": #a11, "green": #0f0, "blue": #00f)

@debug map.set($colors, "warning", #ff5);
// ("red": #f00, "green": #0f0, "blue": #00f, "warning": #ff5)
1
2
3
4
5
6
7
8
9
10
11
12
13

# 合并 map

可以使用 map.merge($map1, $map2) 函数合并 map 并返回合并后的新 map 。

@use "sass:map";

$colors: (
  "red": #f00,
  "green": #0f0,
  "blue": #00f,
);

$colors2: (
  "yellow": #ff0,
  "skyblue": #0ff
);

@debug map.merge($colors, $colors2);
// ("red": #f00, "green": #0f0, "blue": #00f, "yellow": #ff0, "skyblue": #0ff)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 不可变性

和 list 一样,Sass 中的 map 被创建后是不可变的,所以所有的 map 方法都不是直接修改原 map , 而是操作完成后返回一个新的 map 出来。

所以通常应该将新创建的 map 赋值给原变量进行覆盖。

# Function

Sass 本身已经有很多内置的函数可供使用,比如 rgba() , nth() , if() 等。

@function 的定义方式和 @mixin 非常类似,但是调用的时候不需要 @include 而是直接调用。

@function my-color () {
  @return #f00;
}

.div {
  background-color: my-color();
}
1
2
3
4
5
6
7

@function@mixin 不同之处在于,函数返回的只能是一个值,而不是一段 css 样式代码,也就是说函数返回的结果只能作为变量值或属性值。

# Boolean

布尔值是逻辑值 truefalse 。除了它们的字面量形式,布尔值还可以由比较运算符和关系操作符以及许多内置函数(如 math.comparable()map. haskey() )返回。

@use "sass:math";

@debug 1px == 2px; // false
@debug 1px == 1px; // true
@debug 10px < 3px; // false
@debug math.comparable(100px, 3in); // true
1
2
3
4
5
6

使用 boolean 操作符

@debug true and true; // true
@debug true and false; // false
@debug true or false; // true
@debug false or false; // false
@debug not true; // false
@debug not false; // true
1
2
3
4
5
6

# 使用布尔值

结合 @if 等操作,可以使用布尔值作出很多不同情况下的操作。

@mixin avatar($size, $circle: false) {
  width: $size;
  height: $size;

  @if $circle {
    border-radius: $size / 2;
  }
}

.square-av {
  @include avatar(100px, $circle: false);
}
.circle-av {
  @include avatar(100px, $circle: true);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

或者使用 @if() 函数,类似于三元运算符:

@debug if(true, 10px, 30px); // 10px
@debug if(false, 10px, 30px); // 30px
1
2

# Truthy 和 Falsy

和其他语言不同的是,在 Sass 中,只有 falsenull 被看作 Falsy 值,其他都是 Truthy 值,比如,空字符层,0 等值都是 Truthy 值。

# null

null 值也是该类型的唯一值。它表示没有值,通常由函数返回,表示没有结果。

@use "sass:map";
@use "sass:string";

@debug string.index("Helvetica Neue", "Roboto"); // null
@debug map.get(("large": 20px), "small"); // null
@debug &; // null
1
2
3
4
5
6

如果列表中包含一个空值,则生成的CSS中将省略这个空值。

$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas");

h3 {
  font: 18px bold map-get($fonts, "sans");
}
1
2
3
4
5

生成的 css :

h3 {
  font: 18px bold;
}
1
2
3

如果属性值为空,则完全省略该属性。

$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas");

h3 {
  font: {
    size: 18px;
    weight: bold;
    family: map-get($fonts, "sans");
  }
}
1
2
3
4
5
6
7
8
9

编译后的 css :

h3 {
  font-size: 18px;
  font-weight: bold;
}
1
2
3
4